package wiki.xsx.core.bytecode;

import javassist.ClassPool;
import javassist.LoaderClassPath;
import lombok.SneakyThrows;
import net.bytebuddy.agent.ByteBuddyAgent;
import wiki.xsx.core.bytecode.handler.ClassHandler;
import wiki.xsx.core.bytecode.handler.ConstructorHandler;
import wiki.xsx.core.bytecode.handler.FieldHandler;
import wiki.xsx.core.bytecode.handler.MethodHandler;
import wiki.xsx.core.bytecode.transformer.AbstractTransformer;
import wiki.xsx.core.bytecode.transformer.ResetTransformer;

import java.lang.instrument.Instrumentation;

/**
 * 字节码工具
 *
 * @author xsx
 * @date 2023/1/31
 * @since 1.8
 * <p>
 * Copyright (c) 2023 xsx All Rights Reserved.
 * easy-bytecode is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 * http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * </p>
 */
public class BytecodeUtil {

    /**
     * 类池
     */
    private static final ClassPool POOL = initClassPool();
    /**
     * 代理
     */
    private static final Instrumentation INSTRUMENTATION = ByteBuddyAgent.install();

    /**
     * 获取类助手
     *
     * @return 返回类助手
     */
    public static ClassHandler getClassHandler() {
        return new ClassHandler();
    }

    /**
     * 获取属性助手
     *
     * @return 返回属性助手
     */
    public static FieldHandler getFieldHandler() {
        return new FieldHandler();
    }

    /**
     * 获取构造方法助手
     *
     * @return 返回构造方法助手
     */
    public static ConstructorHandler getConstructorHandler() {
        return new ConstructorHandler();
    }

    /**
     * 获取普通方法助手
     *
     * @return 返回普通方法助手
     */
    public static MethodHandler getMethodHandler() {
        return new MethodHandler();
    }

    /**
     * 重置（还原修改）
     * <p>注：如果修改的全局属性，已创建的对象将无法还原</p>
     *
     * @param className 全类名
     */
    public static void reset(String className) {
        transform(new ResetTransformer(null, null, className));
    }

    /**
     * 转换
     *
     * @param transformer 类转换器
     */
    @SneakyThrows
    public static synchronized void transform(AbstractTransformer transformer) {
        INSTRUMENTATION.addTransformer(transformer, true);
        INSTRUMENTATION.retransformClasses(transformer.getClassType());
        INSTRUMENTATION.removeTransformer(transformer);
    }

    /**
     * 获取类池
     *
     * @return 返回类池
     */
    public static ClassPool getClassPool() {
        return POOL;
    }

    /**
     * 获取代理
     *
     * @return 返回代理
     */
    public static Instrumentation getInstrumentation() {
        return INSTRUMENTATION;
    }

    /**
     * 初始化类池
     *
     * @return 返回类池
     */
    private static ClassPool initClassPool() {
        ClassPool pool = new ClassPool(true);
        pool.insertClassPath(new LoaderClassPath(Thread.currentThread().getContextClassLoader()));
        return pool;
    }
}
